package com.sc.nft.config.sand;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sc.nft.entity.*;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

@UtilityClass
@Slf4j
public class SandPayUtil {

    private final static String DATETIME_FORMAT = "yyyyMMddHHmmss";
    //默认配置的是UTF-8
    public static String encoding = "UTF-8";
    //签名类型,默认01-SHA1+RSA
    public static String signType = "01";
    //版本号 默认 1.0
    public static String VERSION = "1.0";
    //http连接超时时间
    public static int connectTimeout = 300000;
    //http响应超时时间
    public static int readTimeout = 600000;
    public static String SAND_DRAW = "00000004";        //对私付款
    public static String drawReqAddr = "/agentpay";
    public static String drawQueryReqAddr = "/queryOrder";

    public static String TRADE_REFUND = "00000018";

    //----------------------------------------绑卡----------------------------------------
    public static String BIND_CARD = "00000018";
    public static String APPLY_BIND_METHOD = "sandPay.fastPay.apiPay.applyBindCard";
    public static String APPLY_BIND_PATH = "/applyBindCard";
    public static String CONFIRM_BIND_METHOD = "sandPay.fastPay.apiPay.confirmBindCard";
    public static String CONFIRM_BIND_PATH = "/confirmBindCard";
    public static String UN_BIND_METHOD = "sandPay.fastPay.apiPay.unbindCard";
    public static String UN_BIND_PATH = "/unbindCard";
    public static String PAY_SMS_METHOD = "sandPay.fastPay.common.sms";
    public static String PAY_SMS_PATH = "/sms";
    public static String PAY_METHOD = "sandPay.fastPay.apiPay.pay";
    public static String PAY_PATH = "/pay";
    public static String TRADE_REFUND_METHOD = "sandpay.trade.refund";
    //-----------------------------------------------------------------------------------

    //----------------------------------------C2B----------------------------------------
    public static String C2B_PRODUCT_CODE = "00002046";
    public static String C2B_METHOD = "sandPay.cloud.acc.pay.createOrder";
    public static String C2B_CONFIRM_METHOD = "sandPay.cloud.acc.pay.confirm";

    //-----------------------------------------------------------------------------------

    //----------------------------------------分账----------------------------------------
    public static String SPLIT_CREATE_METHOD = "sandpay.multipart.create";
    public static String SPLIT_CREATE_PATH = "/multipart/create";
    public static String SPLIT_QUERY_METHOD = "sandpay.multipart.query";
    public static String SPLIT_QUERY_PATH = "/multipart/query";
    public static String SPLIT_FINISH_METHOD = "sandpay.multipart.finish";
    public static String SPLIT_FINISH_PATH = "/multipart/finish";
    public static String SPLIT_REFUND_METHOD = "sandpay.multipart.return";
    public static String SPLIT_REFUND_PATH = "/multipart/return";

    public JSONObject getHeader(String method, String productId) {
        JSONObject header = new JSONObject();
        header.put("version", VERSION);            //版本号
        header.put("method", method);            //接口名称:统一下单
        header.put("mid", SDKConfig.getConfig().getMid());    //商户号
        String plMid = SDKConfig.getConfig().getPlMid();        //平台商户号
        if (plMid != null && StrUtil.isNotEmpty(plMid)) {  //平台商户存在时接入
            header.put("accessType", "2");                    //接入类型设置为平台商户接入
            header.put("plMid", plMid);
        } else {
            header.put("accessType", "1");                    //接入类型设置为平台商户接入												//接入类型设置为普通商户接入
        }
        header.put("channelType", "07");                    //渠道类型：07-互联网   08-移动端
        header.put("reqTime", DateTime.now().toString(DATETIME_FORMAT));    //请求时间
        header.put("productId", productId);                //产品编码
        return header;
    }



    public JSONObject getQueryDrawRequest(String orderNo, String tranTime) {
        JSONObject request = new JSONObject();
        request.put("version", "01");
        request.put("productId", SAND_DRAW);
        request.put("tranTime", tranTime);
        request.put("orderCode", orderNo);
        request.put("extend", "");
        return request;
    }

    public JSONObject getDrawRequest(String tranTime, String orderNo, BigDecimal amount, String cardNo, String name) {
        JSONObject request = new JSONObject();
        request.put("version", "01");
        request.put("productId", SAND_DRAW);
        request.put("tranTime", tranTime);
        request.put("orderCode", orderNo);
        request.put("tranAmt", StrUtil.fillBefore(String.valueOf(amount.multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("currencyCode", "156");
        request.put("accAttr", "0");
        request.put("accType", "4");
        request.put("accNo", cardNo);
        request.put("accName", name);
        request.put("provNo", "");
        request.put("cityNo", "");
        request.put("bankName", "");
        request.put("bankType", "");
        request.put("remark", "提现");
        request.put("payMode", "");
        request.put("channelType", "");
        request.put("extendParams", "");
        request.put("reqReserved", "");
        request.put("extend", "");
        request.put("phone", "");
        return request;
    }

    /**
     * 申请绑卡
     */
    public JSONObject getBindCardRequest(BankBindApply bankBindApply, UserInfo userInfo) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("applyNo", bankBindApply.getApplyNo());
        request.put("cardNo", bankBindApply.getCardNo());
        request.put("userName", bankBindApply.getName());
        request.put("phoneNo", bankBindApply.getPhoneNo());
        request.put("certificateType", "01");
        request.put("certificateNo", bankBindApply.getCertificateNo());
        request.put("creditFlag", "1");
        return request;
    }

    /**
     * 确认绑卡
     */
    public JSONObject getConfirmCardRequest(BankBindApply bankBindApply, UserInfo userInfo, String smsCode) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("sdMsgNo", bankBindApply.getSdMsgNo());
        request.put("phoneNo", bankBindApply.getPhoneNo());
        request.put("smsCode", smsCode);
        return request;
    }

    /**
     * 解绑
     */
    public JSONObject getUnBindRequest(BankBindApply bankBindApply, UserInfo userInfo, String bid) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("applyNo", bankBindApply.getApplyNo());
        request.put("bid", bid);
        request.put("notifyUrl", SandConfig.UN_BIND_NOTIFY_URL);
        return request;
    }

    /**
     * C2B下单
     */
    public JSONObject c2bCreateOrder(PayOrder payOrder, String name, UserInfo userInfo) {
        JSONObject request = new JSONObject();
        request.put("payTool", "0409");
        request.put("orderCode", payOrder.getTradeNo());
        request.put("masterAccount", userInfo.getSandMasterAccount());
        request.put("totalAmount", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("subject", name);
        request.put("body", name);
        request.put("notifyUrl", payOrder.getNotifyUrl());
        request.put("frontUrl", payOrder.getFrontUrl());
        request.put("accountAmt", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        return request;
    }

    public JSONObject c2bCreateOrder(MallPayOrderRecord payOrder, String name, UserInfo userInfo) {
        JSONObject request = new JSONObject();
        request.put("payTool", "0409");
        request.put("orderCode", payOrder.getTradeNo());
        request.put("masterAccount", userInfo.getSandMasterAccount());
        request.put("totalAmount", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("subject", name);
        request.put("body", name);
        request.put("notifyUrl", payOrder.getNotifyUrl());
        request.put("frontUrl", payOrder.getFrontUrl());
        request.put("accountAmt", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        return request;
    }


    /**
     * 绑卡支付发送短信
     */
    public JSONObject getSendSmsRequest(UserBankCard userBankCard, UserInfo userInfo, String orderNo) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("phoneNo", userBankCard.getMobile());
        request.put("bid", userBankCard.getSandBid());
        request.put("orderCode", orderNo);
        return request;
    }

    /**
     * c2b短信认证
     */
    public JSONObject balancePayConfirm(UserInfo userInfo, PayOrder payOrder, String smsCode) {
        JSONObject request = new JSONObject();
        request.put("masterAccount", userInfo.getSandMasterAccount());
        request.put("oriCustomerOrderNo", payOrder.getOrderNo());
        request.put("oriTotalAmount", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("smsCode", smsCode);
        return request;
    }


    /**
     * 绑卡支付
     */
    public JSONObject getFastPayRequest(PayOrder payOrder, String title, UserBankCard userBankCard, UserInfo userInfo, String smsCode, Boolean needSplit) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("orderCode", payOrder.getTradeNo());
        request.put("bid", userBankCard.getSandBid());
        request.put("smsCode", smsCode);
        request.put("phoneNo", userBankCard.getMobile());
        request.put("orderTime", DateTime.now().toString("yyyyMMddHHmmss"));
        request.put("totalAmount", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("subject", title);
        request.put("body", title);
        request.put("currencyCode", "156");
        request.put("clearCycle", "0");
        request.put("notifyUrl", payOrder.getNotifyUrl());
        if (needSplit) {
            //开启分账功能
            request.put("accsplitInfo", "{\"accsplitFlag\":\"1\",\"frozenDays\":\"60\"}");
        }
        return request;
    }


    /**
     * IP商城绑卡支付
     */
    public JSONObject getMallFastPayRequest(MallPayOrderRecord payOrder, String title, UserBankCard userBankCard, UserInfo userInfo, String smsCode) {
        JSONObject request = new JSONObject();
        request.put("userId", userInfo.getOutSideKey());
        request.put("orderCode", payOrder.getTradeNo());
        request.put("bid", userBankCard.getSandBid());
        request.put("smsCode", smsCode);
        request.put("phoneNo", userBankCard.getMobile());
        request.put("orderTime", DateTime.now().toString("yyyyMMddHHmmss"));
        request.put("totalAmount", StrUtil.fillBefore(String.valueOf(payOrder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("subject", title);
        request.put("body", title);
        request.put("currencyCode", "156");
        request.put("clearCycle", "0");
        request.put("notifyUrl", payOrder.getNotifyUrl());
        return request;
    }

    /**
     * IP商城退款 参数拼装
     *
     * @param payOrder
     * @param oriOrderCode 原商户订单号
     * @param refundReason 原因
     * @return
     */
    public JSONObject getMallRefundRequest(MallPayOrderRecord payOrder, String oriOrderCode, String refundReason) {
        JSONObject request = new JSONObject();
        //商户订单号
        request.put("orderCode", payOrder.getTradeNo());
        //原商户订单号
        request.put("oriOrderCode", oriOrderCode);
        //金额
        request.put("refundAmount", StrUtil.fillBefore(String.valueOf(payOrder.getRefundAmount().multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        request.put("notifyUrl", payOrder.getNotifyUrl());
        //原因
        request.put("refundReason", refundReason);
        return request;
    }

    public JSONObject getSplitCreateRequest(OrderSplitFlow orderSplitFlow, String accSplitMerNo) {
        JSONObject request = new JSONObject();
        //分账单号
        request.put("orderCode", orderSplitFlow.getSplitNo());
        //需要分账的订单 原商户订单号
        request.put("oriOrderCode", orderSplitFlow.getPayNo());
        //分账域
        JSONObject accSplitInfo = new JSONObject();
        accSplitInfo.put("accsplitMode","0");
        //0 单次  1-多次 需要测试2个值的区别
        accSplitInfo.put("accsplitMore",1);
        //-分账规则
        JSONObject accsplitRules = new JSONObject();
        //--分账计算模式
        accsplitRules.put("accsplitRule","0");
        accsplitRules.put("accsplitTotalAmt",StrUtil.fillBefore(String.valueOf(orderSplitFlow.getSettleAmount().
                multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        //---分账明细
        JSONArray accsplitRuleMerchantList = new JSONArray();
        JSONObject splitObject = new JSONObject();
        //用户钱包编码
        splitObject.put("accsplitMerNo",accSplitMerNo);
        //优先固定金额
        splitObject.put("fixedAmt","000000000000");
        //分账金额
        splitObject.put("accsplitAmt",StrUtil.fillBefore(String.valueOf(orderSplitFlow.getSettleAmount().
                multiply(BigDecimal.valueOf(100)).intValue()), '0', 12));
        accsplitRuleMerchantList.add(splitObject);
        //填充分账明细
        accsplitRules.put("accsplitRuleMerchantList",accsplitRuleMerchantList);
        //填充分账规则
        accSplitInfo.put("accsplitRules",accsplitRules);
        return request;
    }

    public JSONObject getSplitQueryRequest(String splitNo) {
        JSONObject request = new JSONObject();
        //分账订单号
        request.put("orderCode", splitNo);
        return request;
    }

    public static JSONObject drawRequest(JSONObject request) {

        String reqData = request.toJSONString();
        log.info("请求数据：\n" + reqData);
        try {

            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = reqData.getBytes("UTF-8");
            String encryptData = new String(Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");

            String sign = new String(Base64.encodeBase64(
                    CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");

            String encryptKey = new String(Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");

            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "RTPM"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", SDKConfig.getConfig().getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", SDKConfig.getConfig().getPlMid());  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            String result;
            try {
                result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi" + drawReqAddr, reqMap, connectTimeout, readTimeout);
                result = URLDecoder.decode(result, encoding);
            } catch (IOException e) {
                log.error(e.getMessage());
                return null;
            }

            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = responseMap.get("encryptKey");
            String retEncryptData = responseMap.get("encryptData");
            String retSign = responseMap.get("sign");

            byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");
            log.info("retData:[" + respData + "]");

            byte[] signBytes = Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (!isValid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            log.info("sand draw return data {}", respJson);
            return respJson;

        } catch (Exception e) {

            log.error(e.getMessage());
            return null;
        }
    }

    @SneakyThrows
    public static JSONObject shanDeRe(String result) {
        Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

        String retEncryptKey = responseMap.get("encryptKey");
        String retEncryptData = responseMap.get("encryptData");
        String retSign = responseMap.get("sign");

        byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                .getBytes("UTF-8"));

        byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                "RSA/ECB/PKCS1Padding");

        byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData
                .getBytes("UTF-8"));

        byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

        String respData = new String(respDataBytes, "UTF-8");
        log.info("retData:[" + respData + "]");

        byte[] signBytes = Base64.decodeBase64(retSign
                .getBytes("UTF-8"));

        boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                CertUtil.getPublicKey(), "SHA1WithRSA");

        if (!isValid) {
            log.error("verify sign fail.");
            return null;
        }
        log.info("verify sign success");
        JSONObject respJson = JSONObject.parseObject(respData);
        log.info("sand draw return data {}", respJson);
        return respJson;

    }

    public static JSONObject drawQueryRequest(JSONObject request) {

        String reqData = request.toJSONString();
        log.info("请求数据：\n" + reqData);
        try {

            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = reqData.getBytes("UTF-8");
            String encryptData = new String(Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");

            String sign = new String(Base64.encodeBase64(
                    CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");

            String encryptKey = new String(Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");

            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "ODQU"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", SDKConfig.getConfig().getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", SDKConfig.getConfig().getPlMid());  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            String result;
            try {
                result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi" + drawQueryReqAddr, reqMap, connectTimeout, readTimeout);
                result = URLDecoder.decode(result, encoding);
            } catch (IOException e) {
                log.error(e.getMessage());
                return null;
            }

            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = responseMap.get("encryptKey");
            String retEncryptData = responseMap.get("encryptData");
            String retSign = responseMap.get("sign");

            byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");
            log.info("retData:[" + respData + "]");

            byte[] signBytes = Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (!isValid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            log.info("sand draw return data {}", respJson);
            return respJson;

        } catch (Exception e) {

            log.error(e.getMessage());
            return null;
        }
    }

    public JSONObject fastPayRequest(JSONObject header, JSONObject body, String reqAddr) {

        Map<String, String> reqMap = new HashMap<String, String>();
        JSONObject reqJson = new JSONObject();
        reqJson.put("head", header);
        reqJson.put("body", body);
        String reqStr = reqJson.toJSONString();
        String reqSign;
        // 签名
        try {
            reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(), "SHA1WithRSA")));
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
        //整体报文格式
        reqMap.put("charset", encoding);
        reqMap.put("data", reqStr);
        reqMap.put("signType", signType);
        reqMap.put("sign", reqSign);
        reqMap.put("extend", "");

        String result;
        try {
            log.info("请求报文：\n" + JSONObject.toJSONString(reqSign));
            result = HttpClient.doPost(SDKConfig.getConfig().getFasturl() + reqAddr, reqMap, connectTimeout, readTimeout);
            log.info("响应报文：\n" + result);
            result = URLDecoder.decode(result, encoding);
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }
        Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
        String respData = respMap.get("data");
        String respSign = respMap.get("sign");

        // 验证签名
        boolean valid;
        try {
            valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
            if (!valid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            if (respJson != null) {
                log.info("响应码：[" + respJson.getJSONObject("head").getString("respCode") + "]");
                log.info("响应描述：[" + respJson.getJSONObject("head").getString("respMsg") + "]");
                log.info("响应报文：\n" + JSONObject.toJSONString(respJson, true));
            } else {
                log.error("服务器请求异常！！！");
            }
            return respJson;

        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }
    public JSONObject splitRequest(JSONObject header, JSONObject body, String reqAddr) {

        Map<String, String> reqMap = new HashMap<String, String>();
        JSONObject reqJson = new JSONObject();
        reqJson.put("head", header);
        reqJson.put("body", body);
        String reqStr = reqJson.toJSONString();
        String reqSign;
        // 签名
        try {
            reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(), "SHA1WithRSA")));
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
        //整体报文格式
        reqMap.put("charset", encoding);
        reqMap.put("data", reqStr);
        reqMap.put("signType", signType);
        reqMap.put("sign", reqSign);
        reqMap.put("extend", "");

        String result;
        try {
            log.info("请求报文：\n" + JSONObject.toJSONString(reqSign));
            result = HttpClient.doPost(SDKConfig.getConfig().getFasturl() + reqAddr, reqMap, connectTimeout, readTimeout);
            log.info("响应报文：\n" + result);
            result = URLDecoder.decode(result, encoding);
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }
        Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
        String respData = respMap.get("data");
        String respSign = respMap.get("sign");

        // 验证签名
        boolean valid;
        try {
            valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
            if (!valid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            if (respJson != null) {
                log.info("响应码：[" + respJson.getJSONObject("head").getString("respCode") + "]");
                log.info("响应描述：[" + respJson.getJSONObject("head").getString("respMsg") + "]");
                log.info("响应报文：\n" + JSONObject.toJSONString(respJson, true));
            } else {
                log.error("服务器请求异常！！！");
            }
            return respJson;

        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    /**
     * C2B
     *
     * @param header
     * @param body
     * @param reqAddr
     * @return
     */

    public String c2bRequest(JSONObject header, JSONObject body, String reqAddr) {

        Map<String, String> reqMap = new HashMap<String, String>();
        JSONObject reqJson = new JSONObject();
        reqJson.put("head", header);
        reqJson.put("body", body);
        String reqStr = reqJson.toJSONString();
        String reqSign;
        // 签名
        try {
            reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(), "SHA1WithRSA")));
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
        //整体报文格式
        reqMap.put("charset", encoding);
        reqMap.put("data", reqStr);
        reqMap.put("signType", signType);
        reqMap.put("sign", reqSign);
        reqMap.put("extend", "");
        String result;
        try {
            result = HttpClient.doPost("https://cashier.sandpay.com.cn/gw/cloudAcc/" + reqAddr, reqMap, connectTimeout, readTimeout);
            result = URLDecoder.decode(result, encoding);
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }
        Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
        String respData = respMap.get("data");
        String respSign = respMap.get("sign");

        // 验证签名
        boolean valid;
        try {
            valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
            if (!valid) {
                log.error("verify sign fail.");
                return null;
            }
            JSONObject respJson = JSONObject.parseObject(respData);
            if (respJson != null) {
                log.info("响应码：[" + respJson.getJSONObject("head").getString("respCode") + "]");
                log.info("响应描述：[" + respJson.getJSONObject("head").getString("respMsg") + "]");
                log.info("响应报文：\n" + JSONObject.toJSONString(respJson, true));
            } else {
                log.error("服务器请求异常！！！");
            }
            return respJson.toJSONString();

        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }


    /**
     * 退款发送请求
     *
     * @param oriOrderCode 原商户订单号
     * @param refundReason 原因
     * @return
     */
    public JSONObject refundRequest(MallPayOrderRecord payOrder, String oriOrderCode, String refundReason) {

        Map<String, String> reqMap = new HashMap<String, String>();
        JSONObject reqJson = new JSONObject();
        reqJson.put("head", getHeader(TRADE_REFUND_METHOD, TRADE_REFUND));
        reqJson.put("body", getMallRefundRequest(payOrder, oriOrderCode, refundReason));
        String reqStr = reqJson.toJSONString();
        log.info("退款请求报文：\n" + reqStr);
        String reqSign;
        // 签名
        try {
            reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(), "SHA1WithRSA")));
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
        //整体报文格式
        reqMap.put("charset", encoding);
        reqMap.put("data", reqStr);
        reqMap.put("signType", signType);
        reqMap.put("sign", reqSign);
        reqMap.put("extend", "");

        String result;
        try {
            log.info("请求报文：\n" + JSONObject.toJSONString(reqSign));
            result = HttpClient.doPost("https://cashier.sandpay.com.cn/gateway/api/order/refund", reqMap, connectTimeout, readTimeout);
            log.info("响应报文：\n" + result);
            result = URLDecoder.decode(result, encoding);
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }
        Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
        String respData = respMap.get("data");
        String respSign = respMap.get("sign");

        // 验证签名
        boolean valid;
        try {
            valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
            if (!valid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            if (respJson != null) {
                log.info("响应码：[" + respJson.getJSONObject("head").getString("respCode") + "]");
                log.info("响应描述：[" + respJson.getJSONObject("head").getString("respMsg") + "]");
                log.info("响应报文：\n" + JSONObject.toJSONString(respJson, true));
            } else {
                log.error("服务器请求异常！！！");
            }
            return respJson;

        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }


    public static JSONObject requestServer(JSONObject request) {

        String reqData = request.toJSONString();
        try {

            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = reqData.getBytes("UTF-8");
            String encryptData = new String(Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");

            String sign = new String(Base64.encodeBase64(
                    CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");

            String encryptKey = new String(Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");


            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "MBQU"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", SDKConfig.getConfig().getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", SDKConfig.getConfig().getPlMid());  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            String result;
            try {
                result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/queryBalance", reqMap, connectTimeout, readTimeout);
                result = URLDecoder.decode(result, encoding);
            } catch (IOException e) {
                return null;
            }
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = (String) responseMap.get("encryptKey");
            String retEncryptData = (String) responseMap.get("encryptData");
            String retSign = (String) responseMap.get("sign");
            byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");

            byte[] signBytes = Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (!isValid) {
                System.err.println("verify sign fail.");
                return null;
            }
            System.err.println("verify sign success");

            JSONObject respJson = JSONObject.parseObject(respData);
            return respJson;

        } catch (Exception e) {

            return null;
        }
    }


}
